/*
 * Copyright (c) 2011-2012 Alexander Dubu
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * o  Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * o  Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * o  Neither the name Axil nor the names of its contributors may be used to
 *    endorse or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package axil.tool.axili.command;

import axil.definition.FunctionDefinition;
import axil.definition.Parameter;
import axil.engine.Repository;
import axil.tool.axili.Axili;

import java.util.List;

import static axil.framework.Functions.*;


/**
 * Describe a function in detail.
 */
public class Describe extends Command {
	public Describe() {
		super("describe", "desc",
		      "Describe the given function in detail, including parameters," +
		      "return value. Examples are also provided.",
		      "function");
	}


	/**
	 * Execute this command with the given arguments. The argument count exactly
	 * matches the requirements for this command.
	 */
	public void execute(Axili tool, String[] args) {
		tool.config().seal();
		FunctionDefinition def = Repository.instance().function(args[1]);
		if (def == null) {
			tool.print("There is no function named " + quote(args[1]) + '.');
			return;
		}
		synopsis(tool, def);
		parameters(tool, def);
		returns(tool, def);
		description(tool, def);
		// TODO: Examples are printing out poorly. Do not show them for now.
		// examples(tool, def);
	}


	private void synopsis(Axili tool, FunctionDefinition func) {
		tool.print("SYNOPSIS");
		tool.print("    " + func.synopsis());
		tool.print();
	}


	private void parameters(Axili tool, FunctionDefinition func) {
		List<Parameter> params = func.parameters();
		if (! params.isEmpty()) {
			tool.print("PARAMETERS");
			for (Parameter p : params) {
				tool.print("    " + p.identity() + " (" + p.type() + ')');
				print(tool, describe(p));
			}
		}
	}


	private List<String> describe(Parameter p) {
		StringBuilder b = new StringBuilder(p.description());
		switch(p.kind()) {
		case optional:
			b.append(" The parameter is optional.");
			break;

		case repeating:
			b.append(" This parameter can be repeated more than once.");
			break;

		case required:
			b.append(" A value for this parameter is required.");
			break;

		default:
			throw unreachable();
		}
		return indent(wrap(b.toString(), 60), 2);
	}


	private void returns(Axili tool, FunctionDefinition func) {
		tool.print("RETURNS");
		print(tool, indent(wrap(func.returns().description() +
		                        " A value of type " + func.returns().type() + " is returned.",
		                        60), 1));
	}


	private void description(Axili tool, FunctionDefinition func) {
		tool.print("DESCRIPTION");
		print(tool, indent(wrap(func.description(), 60), 1));
	}


	// TODO: The formatting in the example XML is being torn out
	/*
	private void examples(Axili tool, FunctionDefinition func)
	{
		List<Example> examples = func.examples();
		if (! examples.isEmpty())
		{
			tool.print("EXAMPLES");
			for (Example ex : examples)
			{
				print(tool, wrap(ex.description()));
				tool.print("    " + ex.source().script().trim());
				tool.print("The returned value for this is example is " +
					ex.result().text() + " (" + ex.result().type() + ").");
				tool.print();
			}
		}
	}
	*/

	private void print(Axili tool, List<String> lines) {
		for (String s : lines) {
			tool.print(s);
		}
		tool.print();
	}
}
